;------------------------------------------------------------------------------ ; ;TELEX TAPE CONTROL UCODE ; ;------------------------------------------------------------------------------ ;TAPE READING AND WRITING CODE ; A-MEM USEAGE: ; 0 DISPATCH ADDR. ; 5 SAVED COPY OF WORD COUNT (WRITE) ; 6 MASK FOR TESTING ERROR STATUS (WRITE) TLXRST: ;RESET the formatter and drive. SPEC[IOB-OUT] D[CONST 1] ROT[35. - 30.] DEST[IOD] $ ;Set the SYSTEM RESET line to fmtr. MAPF[2] D[CONST 8] C800 LLOAD $ ;Get wait count. LOOP[.] $ ;Wait about 8 microseconds. SPEC[IOB-OUT] ALU[0] DEST[IOD] $ ;Clear the signal. MAPF[2] LONG POPJ $ ;727 - OBSOLETE VERSION OF READ .PAIR UIOTRP[MUUO] $ TAPERD: NORM PUSHJ[TLXRGO] $ D[MASK 17.] DEST[IR-ADR] PUSHJ[TRP2] NORM $ ;MOVE STATUS INTO AC. ALU[Q] DEST[AC] ACSEL[AC] MAPF[2] JUMP[MAIN] CYLEN[IOB-OUT] $ ; TLXRGO -- CALLED START TAPE MOTION. WAITS FOR FIRST BYTE. TLXRGO: D[CONST 7] ROT[27.] DEST[Q] $ ;Construct mode information for TELEX formatter SPEC[IOB-OUT] D[CONST 6] ROT[6] ALU[DORQ] DEST[IOD] NORM $ ;Set mode for tape controller to talk to TELEX ;7000,,600 means: ;[Put meaning of command here] MAPF[4] SPEC[IOB-OUT] D[CONST 2] ROT[9.] DEST[IOD Q] CYLEN[IOB-OUT] PUSHJ[TLXGOA] $ ;? Initialize command register ; \ / TLXWAIT: MAPF[2] SPEC[IOB-IN] $ ;MAPF[2] is used to finish clearing ; command register by caller MAPF[1] D[CONST 77] ROT[12.] DEST[AR] NORM $ ;Clear read data ready flag TLXW1: SPEC[IOB-IN] D[AR] ALU[D-1] DEST[AR] C550 COND[OBUS=0] JUMP[TLXW2] $ MAPF[2] D[IOD] DEST[HOLD] C800 $ D[MEM] ROT[27.] MASK[1] COND[OBUS=0] JUMP[TLXW1] C550 $ TLXW2: NORM POPJ $ TLXGOA: MAPF[2] SPEC[IOB-IN] CYLEN[IOB-OUT] $ MAPF[4] D[IOD] DEST[HOLD] $ ;GET STATUS BITS. D[MEM] ROT[13.] C550 -OBUS<0 JUMP[TLXGOA] $ ;WAIT FOR FORMATTER NOT BUSY. SPEC[IOB-OUT] D[CONST 41] ROT[35. - 8.] DEST[IOD] NORM $ ;RESET THE CONTROLLER ERROR CONDITIONS. MAPF[1] SPEC[IOB-OUT] D[CONST 1] ROT[6] ALU[DORQ] DEST[IOD] CYLEN[IOB-OUT] $ ;Start tape going forward TLXL1: MAPF[2] SPEC[IOB-IN] CYLEN[IOB-OUT] $ ;Finish setting tape moving [fall thru case] ;Get status from formatter MAPF[4] D[IOD] DEST[HOLD] LONG $ ;Put it in hold to avoid synchronizer problems D[MEM] ROT[13.] OBUS<0 C550 JUMP[TLXL1] $ ;Wait for formatter to say it's going SPEC[IOB-OUT] ALU[Q] DEST[IOD] NORM $ MAPF[2] CYLEN[IOB-OUT] POPJ $ ;Drop move forward request FMNBWT: ;Wait for formatter to be not busy. MAPF[4] D[IOD] DEST[HOLD] $ ;GET STATUS BITS. SPEC[IOB-IN] D[MEM] ROT[13.] C550 -OBUS<0 JUMP[FMNBWT] $ NORM POPJ $ ;READ A RECORD. STORE UP TO C(IR-ADR) WORDS. TRP2: PUSHJ[TRBYTE] C500 $ MAPF[2] D[MEM] ROT[34] DEST[Q] PUSHJ[TRBYTE] C500 $ MAPF[2] D[MEM] ROT[24] ALU[DORQ] DEST[Q] PUSHJ[TRBYTE] C500 $ MAPF[2] D[MEM] ROT[14] ALU[DORQ] DEST[Q] PUSHJ[TRBYTE] C500 $ MAPF[2] D[MEM] ROT[4] ALU[DORQ] DEST[Q] PUSHJ[TRBYTE] C500 $ MAPF[2] D[IR] MASK[18.] ALU[D-1] DEST[IR-ADR] C600 COND[OBUS18] JUMP[TRP2] $ D[MEM] MASK[4] ALU[DORQ] DEST[MEMSTO] NORM $ D[MA] ALU[D+1] DEST[MA] JUMP[TRP2] NORM $ ;READ 1 BYTE. IF ERROR, EOR, EOF, SET Q_2,HIGHEST LOC WRITTEN+1,1 & POP ; ONE OFF THE STACK AND RETURN. IF BYTE SUCCESSFULLY ; READ, JUST RETURN WITH BYTE IN HOLD. TRBYTE: SPEC[IOB-IN] D[CONST 35] DEST[IOD] LLOAD NORM $ ;Ask tape for a byte and status thereof ;Set loop counter to do timeout ;Set IOD hold register for later use to acknowledge ;byte. (The acknowledge bit is the only bit in the ;constant 35 that is seen by the hardware.) TRBY1: MAPF[2] D[IOD] ALU[NOTD] DEST[HOLD] C800 LOOP[TRBY2] $ ;Read byte and status. Byte comes complemented. ;Result is put in HOLD to avoid synchronizer problems ;Do timeout check and branch if still waiting SPEC[IOB-IN] NORM JUMP[TRCHECK] $ ;Byte wasn't ready in time. Go find out why ; --- TRBY2: SPEC[IOB-IN] D[MEM] ROT[26.] OBUS<0 C550 JUMP[TRBY1] $ ;Check for byte ready (this is a two instruction loop) ;Start getting byte and status again in case we have ; to loop ;;;; MAPF[2] SPEC[IOB-IN] D[IOD] ALU[NOTD] DEST[HOLD] LONG $ MAPF[1] SPEC[IOB-OUT] D[MEM] MASK[10] DEST[HOLD] C550 $ ;MAPF[1] clears byte ready ;Raise acknowledge. Note that IOD was set up at the top ; of the loop to contain acknowledge bit (and some junk ; which the hardware will ignore) ;Extract data byte from other status information MAPF[2] SPEC[IOB-OUT] ALU[0] DEST[IOD] C550 POPJ $ ;Drop acknowledge again. ;WARNING: MAPF[2] must be in instruction at return ; address for this to work. ; --- TRCHECK: MAPF[4] D[IOD] DEST[HOLD] $ ;GET STATUS BITS. SPEC[IOB-IN] D[MEM] ROT[13.] C550 -OBUS<0 JUMP[TRCHECK] $ ;WAIT FOR FORMATTER NOT BUSY. D[MEM] ROT[17.] C550 -OBUS<0 JUMP[TRERR] $ ;CHECK FOR ERROR STATUS. D[MEM] ROT[16.] C550 -OBUS<0 JUMP[TRERR] $ ;CHECK FOR OVERRUN ERROR. D[MEM] ROT[22.] C550 -OBUS<0 JUMP[TREOF] $ ;IF ENDX OF FILE NOT SEEN, WE ARE DONE. TREOR: D[MA] MASK[24] DEST[Q] NORM JUMP[TRDONE] $ ;ENDX OF REC. TRDONE: NORM JPOP[. + 1] $ ;REMOVE ONE RETURN ADDR FROM STACK. NORM POPJ $ ;RETURN UPLEVEL (CODE IN Q) TREOF: D[CONST 60] ROT[36] DEST[Q] NORM JUMP[TRDONE] $ TRERR: D[CONST 50] ROT[36] DEST[Q] NORM JUMP[TRDONE] $ .PAIR UIOTRP[MUUO] $ TAPEMT: ;OPCODE 726 -- MTAPE FUNCTIONS. D[MA] DEST[Q] COND[OBUS=0] JUMP[TAPERW] C550 $ D[CONST 5] ALU[D-Q] COND[OBUS=0] JUMP[TAPEFR] C550 $ D[CONST 6] ALU[D-Q] COND[OBUS=0] JUMP[TAPEBR] C550 $ D[CONST 1] ALU[D-Q] COND[OBUS=0] JUMP[TWREOF] C550 $ JUMP[MAIN] $ ;UNKNOWN CODE -- TREAT AS NOP. TWREOF: ;WRITE AN ENDX OF FILE (TAPE MARK) D[CONST 37] DEST[HOLD] NORM JUMP[TLXMTP] $ TLXMTP: SPEC[IOB-OUT] ALU[0] DEST[IOD] NORM $ MAPF[4] SPEC[IOB-OUT] D[MEM] ROT[9.] DEST[IOD Q] CYLEN[IOB-OUT] PUSHJ[TLXGOA] $ MAPF[2] JUMP[MAIN] $ TAPERW: ;REWIND D[CONST 7] DEST[HOLD] NORM JUMP[TLXMTP] $ TAPEFR: ;SKIP FORWARD ONE RECORD. D[CONST 4] DEST[HOLD] NORM JUMP[TLXMTP] $ TAPEBR: ;SKIP BACKWARD ONE RECORD. D[CONST 5] DEST[HOLD] NORM JUMP[TLXMTP] $ TAPERS: ;OPCODE 727 -- READ STATUS BITS FROM TAPE DRIVE. .DEFINE TSS[A B] [ ;MOVE BIT A OF AR TO BIT B OF Q. D[AR] ROT[1 + A] MASK[1] DEST[HOLD] NORM $ D[MEM] ROT[35. - B] ALU[DORQ] DEST[Q] NORM $ ] SPEC[IOB-OUT] ALU[0] DEST[IOD] NORM $ MAPF[4] SPEC[IOB-OUT] D[CONST 24] ROT[9.] DEST[IOD Q] CYLEN[IOB-OUT] PUSHJ[TLXGOA] $ MAPF[2] SPEC[IOB-IN] ALU[0] DEST[Q] C800 $ MAPF[4] D[IOD] ALU[NOTD] DEST[AR] C800 $ D[AR] ROT[13.] C550 OBUS<0 JUMP[. - 2] $ TSS[ 5 30. ] ;ON LINE TSS[ 0 31. ] ;REWINDING TSS[ 7 32. ] ;FILE PROTECT TSS[ 3 33. ] ;LOAD POINT TSS[ 6 34. ] ;READY TSS[ 4 35. ] ;ENDX OF TAPE ALU[Q] DEST[MEMSTO] NORM COND[-MA-AC] LBJUMP[SMAIN] $ .PAIR UIOTRP[MUUO] $ TAPENR: ;730, AC/COUNT. READ WHOLE RECORD, ;STORING UP TO COUNT WORDS STARTING AT EFF ADR. ;IF AC<>0 RETURN STATUS AS FOR 727. ;SWAP AC AND MA, THEN DO TAPERX. D[MA] DEST[O_AC MA] ACSEL[AC] NORM JUMP[TAPERX] $ .PAIR UIOTRP[MUUO] $ TAPERX: ;732 - (AC) IS START ADDR., E IS # OF WORDS TO READ. NORM PUSHJ[TLXRGO] $ ;GET TAPE STARTED. ALU[AC] ACSEL[AC] DEST[MA] PUSHJ[TRP2] NORM $ ;READ REC. ;MOVE STATUS INTO AC. D[IR] COND[-OBUS18] JUMP[TNRP3] C550 $ ; WAS RECORD TOO LONG ? D[CONST 44] ROT[30.] ALU[DORQ] DEST[Q] NORM $ ;YES, SET BIT 3. TNRP3: ALU[Q] DEST[AC] ACSEL[AC] JPOP[MAIN] NORM $ ;NO, NOT TOO LONG. UTAPWR: UIOTRP[MUUO] $ D[CONST 2] ROT[6] DEST[IOD] SPEC[IOB-OUT] NORM JUMP[TAPEWR] $ ;Copy of thing in dispatch TAPEWR: ;731, AC/ADR, E/+COUNT. WRITE RECORD OF +COUNT ; WORDS, DATA FROM ADR. ;SET AC:=0 IF OPERATION COMPLETED SUCCESSFULLY. ; SET AC:= + HIGHEST ADR READ IF REACHED ; EOT DURING OPERATION (CURRENTLY THIS IS THE ONLY ; ERROR CONDITION.) OPERATION IS COMPLETED EVEN ; IF EOT IS PASSED. SPEC[IOB-OUT] ALU[0] DEST[IOD] NORM $ ;CLEAR CTRL REG. MAPF[4] D[CONST 31] ROT[27.] DEST[Q] CYLEN[IOB-OUT] $ ;Construct mode information for TELEX formatter SPEC[IOB-OUT] D[CONST 2] ROT[18.] ALU[DORQ] DEST[IOD] NORM $ ;Set mode for tape controller to talk to TELEX ;31002,,0 means: ;[Put meaning of command here] MAPF[4] SPEC[IOB-OUT] D[CONST 1] ROT[9.] DEST[IOD Q] CYLEN[IOB-OUT] PUSHJ[TLXGOA] $ ;? Initialize command register D[CONST 1] ROT[9. + 18.] DEST[Q] NORM $ ;Mask bit for testing ROM PAR ERR in fmtr. D[CONST 3] ROT[18.] ALU[DORQ] DEST[6] DEST-A-MEM NORM $ ;Add bits for OVRRUN and DATA CHK - store mask in AMEM(6) D[MA] MASK[18.] DEST[AR 5] DEST-A-MEM NORM $ ;Move wc to AR, and preserve in AMEM(5) for retry. TWRTRY: ALU[AC] ACSEL[AC] DEST[MA] NORM $ ;Fetch first word to be written. TWNW: FIXM1 $ SPEC[IOB-IN] D[MEM] ROT[8] MASK[8] DEST[IOD] PUSHJ[TWBYTE] NORM $ SPEC[IOB-IN] D[MEM] ROT[20] MASK[8] DEST[IOD] PUSHJ[TWBYTE] NORM $ SPEC[IOB-IN] D[MEM] ROT[30] MASK[8] DEST[IOD] PUSHJ[TWBYTE] NORM $ SPEC[IOB-IN] D[MEM] ROT[40] MASK[8] DEST[IOD] PUSHJ[TWBYTE] NORM $ D[AR] ALU[D-1] DEST[AR] C600 COND[OBUS=0] JUMP[TWNW1] $ SPEC[IOB-IN] D[MEM] MASK[4] DEST[IOD] PUSHJ[TWBYTE] NORM $ D[MA] ALU[D+1] DEST[MA] NORM JUMP[TWNW] $ ;Fetch next word. TWNW1: D[MEM] MASK[4] DEST[Q] NORM $ SPEC[IOB-IN] D[CONST 1] ROT[35. - 1] ALU[DORQ] DEST[IOD] NORM PUSHJ[TWBYTE] $ SPEC[IOB-IN] PUSHJ[FMNBWT] $ ;WAIT FOR FORMATTER NOT BUSY. D[MEM] ALU[NOTD] DEST[Q] NORM $ ;Complement of status to Q D[16] ALU[D&Q] C550 COND[-OBUS=0] JUMP[TWERR] $ ;Test err bits. ALU[0] DEST[AC] NORM $ ;We return 0 in AC if no EOT. D[MEM] ROT[4] C550 OBUS<0 JUMP[MAIN] $ ;If no EOT seen, all done. D[MA] MASK[18.] DEST[AC] NORM $ ;EOT seen. Get ending MA. D[CONST 40] ROT[35. - 5] ALU[DORAC] DEST[AC] NORM JUMP[MAIN] $ ;Turn on bit 0 to indicate EOT seen during operation. TWBYTE: MAPF[4] D[IOD] ALU[NOTD] DEST[Q] C800 $ ;Read TP STAT (complemented). D[16] ALU[D&Q] C550 COND[-OBUS=0] JUMP[TWERR] $ ;Test err bits. SPEC[IOB-IN] D[CONST 2] ALU[D&Q] C550 COND[-OBUS=0] JUMP[TWBYTE] $ SPEC[IOB-OUT] SHORT $ MAPF[14] C800 POPJ $ TWERR: SPEC[IOB-IN] NORM PUSHJ[FMNBWT] $ ;WAIT FOR NOT BUSY. NORM PUSHJ[TLXRST] $ ;Blast the tape formatter and drive SPEC[IOB-IN] NORM PUSHJ[FMNBWT] $ ;Wait for formatter idle. SPEC[IOB-OUT] D[CONST 5] ROT[9.] DEST[IOD Q] PUSHJ[TLXGOA] $ ;Start a BACKSPACE RECORD command. SPEC[IOB-IN] NORM PUSHJ[FMNBWT] $ ;Wait for completion. SPEC[IOB-OUT] D[CONST 27] ROT[9.] DEST[IOD Q] PUSHJ[TLXGOA] $ ;Start an ERASE 3.5" GAP command. SPEC[IOB-IN] NORM PUSHJ[FMNBWT] $ ;Wait for completion. SPEC[IOB-OUT] D[CONST 1] ROT[9.] DEST[IOD Q] NORM PUSHJ[TLXGOA] $ ;Start write operation over again. D[15] DEST[AR] NORM JUMP[TWRTRY] $ ;Recover WC and retry op. ;BOOTSTRAP LOADER FOR MACROCODE. .ORG[5000] MBOOT: JUMP[5001] CYLEN[LONG] $ ALU[0] DEST[HI-ABS-MA] PUSHJ[CCLR] NORM $ D[CONST 1] ROT[18.] DEST[HI-ABS-MA] PUSHJ[CCLR] NORM $ D[CONST 7] DEST[DEV-ADR] CYLEN[LONG] PUSHJ[TLXRGO] $ ;SELECT DEVICE 7, START READ. ALU[0] DEST[MA HI-ABS-MA] NORM $ P2: PUSHJ[MBTBYTE] C500 $ MAPF[2] D[MEM] ROT[34] DEST[Q] PUSHJ[MBTBYTE] C500 $ MAPF[2] D[MEM] ROT[24] ALU[DORQ] DEST[Q] PUSHJ[MBTBYTE] C500 $ MAPF[2] D[MEM] ROT[14] ALU[DORQ] DEST[Q] PUSHJ[MBTBYTE] C500 $ MAPF[2] D[MEM] ROT[4] ALU[DORQ] DEST[Q] PUSHJ[MBTBYTE] C500 $ MAPF[2] D[MEM] MASK[4] ALU[DORQ] DEST[MEMSTO] C500 $ D[MA] ALU[D+1] DEST[MA] JUMP[P2] C500 $ CCLR: ALU[0] DEST[MA] NORM $ ALU[0] DEST[MEMSTO] NORM $ D[MA] ALU[D+1] DEST[MA] NORM $ D[MA] MASK[18.] COND[-OBUS=0] JUMP[. - 2] C600 $ POPJ NORM $ MBTBYTE: SPEC[IOB-IN] D[CONST 35] DEST[IOD] LLOAD NORM $ ;Ask tape for a byte and status thereof ;Set loop counter to do timeout ;Set IOD hold register for later use to acknowledge ;byte. (The acknowledge bit is the only bit in the ;constant 35 that is seen by the hardware.) MBTBY1: MAPF[2] D[IOD] ALU[NOTD] DEST[HOLD] C800 LOOP[MBTBY2] $ ;Read byte and status. Byte comes complemented. ;Result is put in HOLD to avoid synchronizer problems ;Do timeout check and branch if still waiting SPEC[IOB-IN] NORM PUSHJ[MBTCHECK] $ ;Byte wasn't ready in time. Go find out why PUSHJ [TLXRGO] $ ;START NEXT RECORD. NORM JUMP[MBTBYTE] $ ;Go for another record ; --- MBTBY2: SPEC[IOB-IN] D[MEM] ROT[26.] OBUS<0 C550 JUMP[MBTBY1] $ ;Check for byte ready (this is a two instruction loop) ;Start getting byte and status again in case we have ; to loop ;;;; MAPF[2] SPEC[IOB-IN] D[IOD] ALU[NOTD] DEST[HOLD] LONG $ MAPF[1] SPEC[IOB-OUT] D[MEM] MASK[10] DEST[HOLD] C550 $ ;MAPF[1] clears byte ready ;Raise acknowledge. Note that IOD was set up at the top ; of the loop to contain acknowledge bit (and some junk ; which the hardware will ignore) ;Extract data byte from other status information MAPF[2] SPEC[IOB-OUT] ALU[0] DEST[IOD] C550 POPJ $ ;Drop acknowledge again. ;WARNING: MAPF[2] must be in instruction at return ; address for this to work. ; --- MBTCHECK: MAPF[4] D[IOD] DEST[HOLD] $ SPEC[IOB-IN] D[MEM] ROT[13.] C550 -OBUS<0 JUMP[MBTCHECK] $ ;WAIT FOR FORMATTER IDLE. D[MEM] ROT[17.] C550 -OBUS<0 JUMP[MBTERR] $ ;CHECK FOR ERROR STATUS. D[MEM] ROT[22.] C550 OBUS<0 POPJ $ ;IF ENDX OF FILE NOT SEEN, RETURN FOR MORE, ELSE DONE. ALU[0] DEST[Q] NORM $ ;CLEAR LIGHTS TO INDICATE NO ERRORS. MBTDNX: SPEC[IOB-OUT] ALU[0] DEST[DEV-ADR] $ ;Setup to display code in lights SPEC[IOB-OUT] MAPF[2] ALU[Q] $ ;LOAD LIGHTS FROM Q, CLR SW FF'S D1: MAPF[4] SPEC[IOB-IN] $ ;CHECK START AND CONT SWITCHES. RD NEXT FILE ON CONT MAPF[4] D[IOD] DEST[AR] $ D[AR] ROT[5] MASK[2] DEST[AR] COND[OBUS=0] JUMP[D1] CYLEN[LONG] $ ;WAIT FOR A SWITCH. D[AR] MASK[1] COND[-OBUS=0] JUMP[MSTART] C550 $ ; ... START MAIN MICROCODE ON START SWITCH. SPEC[IOB-OUT] NORM $ ;CLEAR SWITCH FF'S MAPF[4] JUMP[MBOOT] CYLEN[LONG] $ MBTERR: D[CONST 0] ALU[NOTD] DEST[Q] JUMP[MBTDNX] $ ; --- .RELOC ;RETURN TO OLD LOC. CTR.